Programmierung von CAx-Systemen

David Straub

CAx-Programmierung – D. Straub

Gliederung

  1. Einführung
  2. Topologie
  3. Geometrie
  4. Modellierungsstrategien
  5. Datenaustausch
  6. Simulation
  7. Optimierung
  8. Fertigung
CAx-Programmierung – D. Straub

Topologie

  • Geometrie vs. Topologie
  • Einstieg: Ein konkreter Körper
  • Topologische Grundelemente
  • Hierarchie und Konnektivität
  • Orientierung
  • B-Rep als Industriestandard
  • Topologie in build123d
CAx-Programmierung – D. Straub

Geometrie vs. Topologie

CAx-Programmierung – D. Straub

Was ist der Unterschied?

Topologie beschreibt die Struktur eines Körpers:

  • Wie viele Flächen, Kanten, Ecken hat er?
  • Wie sind diese miteinander verbunden?
  • Welche Elemente begrenzen welche anderen?

Geometrie beschreibt die Form im Raum:

  • Wo liegen die Punkte (Koordinaten)?
  • Welche mathematische Kurve/Fläche liegt zugrunde?
  • Krümmung, Länge, Flächeninhalt

B-Rep = Topologie + Geometrie: Die Topologie liefert das Gerüst, die Geometrie füllt es mit konkreter Form.

CAx-Programmierung – D. Straub

Beispiel: Würfel vs. Quader

Beide haben dieselbe Topologie:

  • 8 Ecken, 12 Kanten, 6 Flächen
  • Jede Fläche von 4 Kanten begrenzt
  • Jede Kante von 2 Ecken begrenzt

Aber unterschiedliche Geometrie:

  • Würfel: alle Flächen quadratisch, alle Kanten gleich lang
  • Quader: Rechteckflächen, unterschiedliche Kantenlängen

→ Gleiche Topologie, verschiedene Geometrie ist möglich!

CAx-Programmierung – D. Straub

Analogie: S-Bahn-Netz

Netzplan (Topologie): Welche Stationen sind verbunden? Wo muss ich umsteigen?

Geografische Karte (Geometrie): Wo liegen die Stationen genau? Wie lang ist die Strecke in km?

Beide Darstellungen beschreiben dasselbe Netz – aber unterschiedliche Aspekte davon.

→ In CAD: B-Rep trennt genauso Struktur (Topologie) von Form (Geometrie).

CAx-Programmierung – D. Straub

Einstieg: Ein konkreter Körper

CAx-Programmierung – D. Straub

Unser erstes Objekt: der Zylinder

import build123d as bd

zylinder = bd.Cylinder(radius=10, height=20)
zylinder

Ein einfacher Zylinder – aber wie ist er intern aufgebaut?

CAx-Programmierung – D. Straub

Topologie inspizieren

print(zylinder.show_topology())

Ausgabe (vereinfacht):

Solid
└── Shell
    ├── Face  (zylindrische Mantelfläche)
    ├── Face  (untere Kreisfläche)
    └── Face  (obere Kreisfläche)
        ├── Wire
        │   └── Edge  (Kreisbogen)
        ...

→ Drei Flächen, jede durch Kanten begrenzt, Kanten durch Ecken.

CAx-Programmierung – D. Straub

Elemente zählen

print("Solids:  ", len(zylinder.solids()))
print("Shells:  ", len(zylinder.shells()))
print("Faces:   ", len(zylinder.faces()))
print("Wires:   ", len(zylinder.wires()))
print("Edges:   ", len(zylinder.edges()))
print("Vertices:", len(zylinder.vertices()))

Ergebnis:

Solids:   1
Shells:   1
Faces:    3
Wires:    3
Edges:    3
Vertices: 2

→ Warum nur 2 Ecken? Warum nur 3 Kanten?

CAx-Programmierung – D. Straub

Anatomie des Zylinders

Solid
└── Shell
    ├── Face: Mantel (Zylinderfläche)  — 1 Kante (Seam-Kante)
    ├── Face: Boden (Kreisfläche)      — 1 Kante (Kreis)
    └── Face: Deckel (Kreisfläche)     — 1 Kante (Kreis)
  • Die Kreiskanten (Boden, Deckel) teilen sich je einen Vertex mit der Mantelkante
  • Die Mantel-Kante ist eine Nahtkante (seam edge)
  • Kanten werden zwischen Flächen geteilt – nicht dupliziert!
CAx-Programmierung – D. Straub

Topologische Grundelemente

CAx-Programmierung – D. Straub

Vertex – der Punkt

  • Nulldimensionales Element
  • Repräsentiert einen Punkt im Raum
  • Geometrie: ein 3D-Punkt
  • Begrenzungselement von Kanten
v = zylinder.vertices()[0]
print(type(v))       # <class 'build123d.topology.zero_d.Vertex'>
print(v.center())    # Position im Raum
CAx-Programmierung – D. Straub

Edge – die Kante

  • Eindimensionales Element
  • Ein Kurvenstück, begrenzt durch Vertices
  • Geometrie: eine parametrische Kurve (Linie, Kreis, Spline, …)
kanten = zylinder.edges()
for k in kanten:
    print(k.geom_type)  # CIRCLE oder LINE oder ...
    print(k.length)
CAx-Programmierung – D. Straub

Wire – der Kantenzug

  • Geordnete, zusammenhängende Folge von Edges
  • Bildet eine geschlossene Schleife (Kontur einer Fläche)
  • Kein eigenes geometrisches Objekt – nur eine Anordnung
wire = zylinder.faces()[0].wires()[0]
print(len(wire.edges()), "Kanten im Wire")

→ Flächen können mehrere Wires haben: äußere Kontur + innere Löcher

CAx-Programmierung – D. Straub

Face – die Fläche

  • Zweidimensionales Element
  • Ein Flächenstück, begrenzt durch Wires
  • Geometrie: eine parametrische Fläche (Ebene, Zylinder, Kugel, Spline, …)
flaechen = zylinder.faces()
for f in flaechen:
    print(f.geom_type)  # PLANE oder CYLINDER oder ...
    print(f.area)
CAx-Programmierung – D. Straub

Shell – die Hülle

  • Zusammenhängende Menge von Faces (verbunden über gemeinsame Edges)
  • Bildet eine geschlossene oder offene Hülle
shell = zylinder.shells()[0]
print(len(shell.faces()), "Flächen in der Shell")

→ Eine geschlossene Shell begrenzt ein Volumen

CAx-Programmierung – D. Straub

Solid – der Körper

  • Dreidimensionales Element
  • Ein Volumenkörper, begrenzt durch eine (oder mehrere) Shells
  • Das Zielobjekt in der parametrischen Konstruktion
solid = zylinder.solids()[0]
print(solid.volume)  # Volumen in mm³
print(solid.area)    # Oberfläche in mm²
CAx-Programmierung – D. Straub

Compound – die Sammlung

  • Container für beliebige Objekte (Shapes, auch gemischter Typen)
  • Kein geometrisches Konzept, nur Verwaltung
  • Part, Sketch, Curve in build123d sind spezialisierte Compounds
quader = bd.Box(30, 20, 10)
gruppe = bd.Compound([zylinder, quader])
print(len(gruppe.solids()), "Solids in der Gruppe")
CAx-Programmierung – D. Straub

Übersicht: Topologie-Hierarchie

Typ Dimension Begrenzt durch Geometrie
Vertex 0D Punkt
Edge 1D Vertices Kurve
Wire 1D Edges
Face 2D Wires Fläche
Shell 2D Faces
Solid 3D Shells
Compound beliebig
CAx-Programmierung – D. Straub

Hierarchie und Konnektivität

CAx-Programmierung – D. Straub

Der Topologie-Graph

Die Elemente bilden eine hierarchische Struktur (gerichteter Graph):

Solid
 └── Shell
      ├── Face
      │    └── Wire
      │         └── Edge
      │              └── Vertex
      └── Face
           └── Wire
                └── Edge
                     └── Vertex  ← derselbe Vertex wie oben!

Entscheidend: Teilelemente werden geteilt, nicht kopiert.

CAx-Programmierung – D. Straub

Konnektivität durch gemeinsame Teilelemente

Zwei Objekte sind verbunden, wenn sie ein gemeinsames Begrenzungselement teilen:

  • Zwei Flächen sind verbunden, wenn sie eine gemeinsame Kante haben
  • Zwei Kanten sind verbunden, wenn sie einen gemeinsamen Vertex haben
quader = bd.Box(20, 20, 10)

# Welche Flächen teilen eine bestimmte Kante?
kante = quader.edges()[0]
for f in quader.faces():
    if kante in f.edges():
        print("Fläche enthält diese Kante:", f.center())
CAx-Programmierung – D. Straub

Teilelemente abfragen

quader = bd.Box(20, 20, 10)

# Alle Kanten einer bestimmten Fläche
oberseite = quader.faces().sort_by(bd.Axis.Z).last
print("Kanten der Oberseite:", len(oberseite.edges()))

# Alle Vertices einer bestimmten Kante
kante = oberseite.edges()[0]
print("Vertices der Kante:", len(kante.vertices()))

→ Die Topologie erlaubt Navigation von oben nach unten durch die Hierarchie

CAx-Programmierung – D. Straub

Topologie vs. Anzahl bei komplexeren Körpern

# Quader nach boolescher Operation
quader = bd.Box(40, 40, 20)
loch = bd.Cylinder(radius=8, height=20)
ergebnis = quader - loch

print("Faces:   ", len(ergebnis.faces()))    # 7
print("Edges:   ", len(ergebnis.edges()))    # 15
print("Vertices:", len(ergebnis.vertices())) # 10

Boolesche Operationen verändern die Topologie – neue Elemente entstehen, alte entfallen.

CAx-Programmierung – D. Straub

Orientierung

CAx-Programmierung – D. Straub

Orientierung: Motivation

Gedankenexperiment: Sechs quadratische Flächen, topologisch zu einer Shell verbunden.

Was entsteht?

  • Ein Würfel (massiv, Material innen)?
  • Eine würfelförmige Aussparung (Hohlraum, Material außen)?

Die Topologie ist identisch – 6 Faces, 12 Edges, 8 Vertices, alles verbunden.

→ Wir brauchen eine zusätzliche Information: in welche Richtung zeigt jede Fläche?

CAx-Programmierung – D. Straub

Orientierung: Normale zeigt nach außen

Die Lösung: Jede Face trägt eine Richtungsinformation – den Normalenvektor.

Regel: In einem gültigen Solid zeigt die Normale immer vom Material weg (nach außen).

  • Würfel: Normalen zeigen nach außen → Material liegt innen ✓
  • Hohlraum: Normalen zeigen nach innen → das ist ein anderes Objekt (z.B. nach Boolean-Differenz)
CAx-Programmierung – D. Straub

Dieselbe Logik eine Ebene tiefer: Welche Seite einer Fläche ist „innen"?

Regel: Wenn man von außen auf eine Face schaut (entgegen der Normalen), liegt das Material links von der Durchlaufrichtung jeder Kante.

  • Outer Wire: Material liegt links → Fläche ist begrenzt
  • Inner Wire: läuft entgegengesetzt → Material liegt rechts → Loch
CAx-Programmierung – D. Straub

Warum ist Orientierung wichtig?

  • Boolesche Operationen brauchen korrekte Orientierung (Vereinigung, Differenz, Schnitt)
  • Wasserdichtheit: Normalen müssen konsistent nach außen zeigen
  • Export: Falsche Orientierung → ungültige STL- oder STEP-Dateien
# build123d prüft automatisch die Orientierung
ergebnis = quader - loch
print(ergebnis.is_valid)  # True wenn korrekt

→ build123d und OCCT kümmern sich meist automatisch darum – aber das Konzept erklärt, warum manche Operationen fehlschlagen.

CAx-Programmierung – D. Straub

B-Rep als Industriestandard

CAx-Programmierung – D. Straub

B-Rep – ein Standard

Die Topologie-Konzepte dieser Vorlesung sind nicht an eine Software gebunden:

Software Kernel Standard
CATIA CGM (Dassault) B-Rep
SolidWorks Parasolid (Siemens) B-Rep
NX (Unigraphics) Parasolid (Siemens) B-Rep
FreeCAD OCCT B-Rep
build123d OCCT B-Rep

→ Vertex, Edge, Wire, Face, Shell, Solid – überall dieselben Konzepte, nur unterschiedliche Syntax.

CAx-Programmierung – D. Straub

STEP: der gemeinsame Nenner

ISO 10303 (STEP) ist das universelle Austauschformat für B-Rep-Geometrie.

  • Exportiert von CATIA, SolidWorks, NX, FreeCAD, CadQuery, build123d …
  • Speichert exakt dieselbe topologische Struktur: Vertices, Edges, Faces, Shells, Solids
  • Kein Informationsverlust bei der Topologie
import build123d as bd

# Eine STEP-Datei aus CATIA laden:
fremdes_teil = bd.import_step("catia_teil.step")

# Und sofort mit denselben Methoden arbeiten:
print(len(fremdes_teil.faces()))   # Flächen zählen
print(len(fremdes_teil.edges()))   # Kanten zählen
fremdes_teil.show_topology()       # Struktur anzeigen
CAx-Programmierung – D. Straub

Kernel-Unterschiede: was variiert?

Das Gleiche (normiert durch B-Rep / ISO 10303):

  • Hierarchie: Vertex → Edge → Wire → Face → Shell → Solid
  • Orientierungskonzept (FORWARD / REVERSED)
  • Boolesche Operationen (Union, Cut, Common)

Das Unterschiedliche (kernel-spezifisch):

  • Welche Kurven-/Flächentypen unterstützt werden
  • Toleranzen und Präzisionsstrategie
  • Interne Datenstrukturen und Algorithmen
  • API-Syntax

→ Wer B-Rep versteht, kann sich in jedem professionellen CAD-System orientieren.

CAx-Programmierung – D. Straub

Topologie in build123d

CAx-Programmierung – D. Straub

Teilelemente selektieren

Jedes Objekt stellt Selektoren bereit, die ShapeList zurückgeben:

part = bd.Box(40, 30, 20) - bd.Cylinder(radius=8, height=20)

part.vertices()   # alle Vertices
part.edges()      # alle Kanten
part.wires()      # alle Wires
part.faces()      # alle Flächen
part.solids()     # alle Körper

ShapeList ist eine Liste mit Zusatzmethoden zum Filtern und Sortieren.

CAx-Programmierung – D. Straub

Selektoren: Sortieren

part = bd.Box(40, 30, 20)

# Nach Position entlang einer Achse
oberseite  = part.faces().sort_by(bd.Axis.Z).last   # höchste Fläche
unterseite = part.faces().sort_by(bd.Axis.Z).first  # tiefste Fläche

# Nach Geometrieeigenschaft
groesste = part.faces().sort_by(bd.SortBy.AREA).last
laengste = part.edges().sort_by(bd.SortBy.LENGTH).last

# Gruppieren
gruppen = part.faces().group_by(bd.SortBy.AREA)  # Liste von Listen
CAx-Programmierung – D. Straub

Selektoren: Filtern

from build123d import GeomType

part = bd.Box(30, 20, 10) - bd.Cylinder(radius=5, height=10)

# Nach Achsausrichtung (Kanten parallel, Flächen normal)
part.edges().filter_by(bd.Axis.Z)       # vertikale Kanten
part.faces().filter_by(bd.Axis.Z)       # Ober-/Unterseite

# Nach Geometrietyp
part.edges().filter_by(GeomType.CIRCLE)    # Kreiskanten
part.faces().filter_by(GeomType.PLANE)     # ebene Flächen
part.faces().filter_by(GeomType.CYLINDER)  # zylindrische Flächen

# Nach Position (Mittelpunkt der Kante/Fläche)
part.edges().filter_by_position(bd.Axis.Z, 4, 6)
CAx-Programmierung – D. Straub

Topologische Stabilität nach Operationen

⚠️ Problem: Nach jeder Operation kann sich die interne Nummerierung der Objekte ändern!

part_v1 = bd.Box(40, 30, 20)
# part_v1.faces()[0]  ← Index 0 ist eine bestimmte Fläche

part_v2 = bd.fillet(part_v1.edges(), radius=2)
# part_v2.faces()[0]  ← Index 0 kann jetzt eine ANDERE Fläche sein!

→ Deshalb: immer semantisch selektieren (sort_by, filter_by), nie hart auf Index verlassen.

CAx-Programmierung – D. Straub

Zusammenfassung

CAx-Programmierung – D. Straub

Topologie vs. Geometrie

Topologie Geometrie
Beschreibt Struktur, Verbindungen Form, Position
Fragt Was ist womit verbunden? Wo liegt was?
Beispiel 6 Flächen, 12 Kanten Fläche liegt bei z=10
Ändert sich bei Bool. Operationen Skalierung, Verschiebung
CAx-Programmierung – D. Straub

Topologische Hierarchie

Solid  →  Shell  →  Face  →  Wire  →  Edge  →  Vertex
  3D         2D        2D      1D      1D        0D
  • Elemente werden geteilt (nicht kopiert)
  • Zwei Objekte sind verbunden durch gemeinsame Teilelemente
  • Orientierung bestimmt, was „innen" und „außen" ist (Loch vs. Material, Hohlraum vs. Solid)
CAx-Programmierung – D. Straub

Selektoren in build123d

part.faces().sort_by(bd.Axis.Z).last              # höchste Fläche
part.edges().filter_by(bd.GeomType.CIRCLE)        # Kreiskanten
part.faces().group_by(bd.SortBy.AREA)[-1]         # größte Flächen
part.edges().filter_by_position(bd.Axis.Z, 4, 6)  # Kanten in Bereich

Robuste Selektion durch semantische Kriterien statt Indizes

CAx-Programmierung – D. Straub

B-Rep – ein universelles Konzept

  • Vertex, Edge, Face, Shell, Solid: dieselben Konzepte in CATIA, SolidWorks, NX, FreeCAD, build123d
  • STEP (ISO 10303) transportiert diese Struktur zwischen Systemen
  • Wer B-Rep-Topologie versteht, kann sich in jedem professionellen CAD-System orientieren
  • build123d ist unser Werkzeug – nicht das Ziel
CAx-Programmierung – D. Straub

Ausblick: Geometrie

In der nächsten Einheit: Wie wird Form mathematisch beschrieben?

  • Kurven: Linien, Kreise, B-Splines
  • Flächen: Ebenen, Zylinder, NURBS-Flächen
  • Parameter und Koordinatensysteme
  • Wie OCCT Geometrie und Topologie verbindet (B-Rep)
CAx-Programmierung – D. Straub

Programmierung von CAx-Systemen

Übung 2: B-Rep Topologie

David Straub

CAx-Programmierung – D. Straub

Lernziele

Nach dieser Übung können Sie:

  • Die topologische Struktur eines B-Rep-Körpers inspizieren und beschreiben
  • Sub-Shapes gezielt nach Position, Achsausrichtung und Geometrietyp selektieren
  • Operationen (Fillet, Chamfer, Aufbauen) auf topologisch selektierte Elemente anwenden
  • Robuste Selektionskriterien formulieren, die nach Modifikationen stabil bleiben
CAx-Programmierung – D. Straub

Startcode

import build123d as bd
from build123d import GeomType
# Unser Ausgangskörper: Montageplatte mit vier Bohrungen
platte = bd.Box(80, 60, 8)

for x, y in [(-27, -20), (27, -20), (-27, 20), (27, 20)]:
    platte = platte - bd.Pos(x, y) * bd.Cylinder(radius=4, height=8)

platte
CAx-Programmierung – D. Straub

Aufgabe 1: Topologie erkunden

CAx-Programmierung – D. Straub

1.1 – Strukturübersicht

Untersuchen Sie die Topologie der Montageplatte:

  1. Rufen Sie show_topology() auf – was sehen Sie?
  2. Zählen Sie die Elemente: Faces, Edges, Vertices, ...
  3. Wie viele Flächen haben Sie erwartet? Was trägt jede Bohrung zur Topologie bei?

Hinweise: .show_topology(), .faces(), .edges(), .vertices(), len()

CAx-Programmierung – D. Straub

1.2 – Geometrietypen

Geben Sie für jede Fläche den Geometrietyp und die Fläche aus. Dasselbe für jede Kante mit Länge.

  1. Welche Geometrietypen kommen bei Flächen vor? Und bei Kanten?
  2. Wie viele Kanten sind Kreise? Passt das zur Anzahl der Bohrungen?

Hinweise: .geom_type, .area, .length, for f in platte.faces():

CAx-Programmierung – D. Straub

Aufgabe 2: Gezielte Selektion

CAx-Programmierung – D. Straub

2.1 – Flächen selektieren

  1. Selektieren Sie die Oberseite der Platte. Geben Sie Typ und Flächeninhalt aus.
  2. Selektieren Sie alle zylindrischen Flächen (Bohrungswände). Wie viele sind es?

Hinweise: .faces(), .sort_by(Axis.Z), .last, .filter_by(GeomType.CYLINDER), .geom_type, .area

CAx-Programmierung – D. Straub

2.2 – Kanten selektieren und verrunden

  1. Selektieren Sie alle kreisförmigen Kanten und verrunden Sie sie mit radius=1.
  2. Verrunden Sie nur die oberen Kreiskanten (Bohrungseintritt oben). Was ist der visuelle Unterschied?

Hinweise: .edges(), .filter_by(GeomType.CIRCLE), .filter_by_position(Axis.Z, min, max), bd.fillet(..., radius=...)

CAx-Programmierung – D. Straub

2.3 – Selektion nach Flächengröße

Selektieren Sie die kleinste und die größte Fläche der Platte. Geben Sie jeweils Typ und Flächeninhalt aus.

Welche Flächen sind das geometrisch?

Hinweise: .sort_by(SortBy.AREA), .first, .last, .area, .geom_type

CAx-Programmierung – D. Straub

Aufgabe 3: Modell erweitern

CAx-Programmierung – D. Straub

3.1 – Zapfen auf der Oberseite

Bauen Sie einen Zylinder (radius=12, height=15) mittig auf der Oberseite der Platte auf.

Frage: Warum bd.Plane(oberseite) statt bd.Plane.XY.offset(8)? Was wäre der Unterschied in einem komplexeren Modell?

Hinweise: .faces().sort_by(Axis.Z).last, bd.Plane(face), ebene * zapfen, basis + ...

CAx-Programmierung – D. Straub

3.2 – Kanten des Zapfens verrunden

  1. Verrunden Sie die Oberkante des Zapfens mit radius=2.
  2. Verrunden Sie zusätzlich die Übergangskante zwischen Platte und Zapfen.

Hinweise: .edges().filter_by(GeomType.CIRCLE), .sort_by(Axis.Z), .last, List-Slicing [-2:], bd.fillet()

CAx-Programmierung – D. Straub

Zusatzaufgabe 1: Flansch mit Lochkreis

CAx-Programmierung – D. Straub

Flansch konstruieren

Konstruieren Sie einen Flansch (Ringscheibe mit Bohrungen auf einem Lochkreis):

import math

# Ringscheibe: großer Zylinder minus kleiner Zylinder
flansch = bd.Cylinder(radius=40, height=12) - bd.Cylinder(radius=18, height=12)

# Lochkreis: 6 Bohrungen im Abstand von 60°
for winkel in range(0, 360, 60):
    x = 30 * math.cos(math.radians(winkel))
    y = 30 * math.sin(math.radians(winkel))
    flansch = flansch - bd.Pos(x, y) * bd.Cylinder(radius=4, height=12)

flansch
CAx-Programmierung – D. Straub

Flansch analysieren und bearbeiten

  1. Wie viele Flächen hat der Flansch? Wie viele davon sind zylindrisch?
  2. Verrunden Sie alle oberen Kreiskanten (Bohrungen + Innen-/Außenring) mit radius=1.
  3. Fügen Sie eine Fase an der Unterkante des Innenrings hinzu.

Hinweise: .filter_by(GeomType.CYLINDER), .filter_by(GeomType.CIRCLE), .filter_by_position(Axis.Z, ...), bd.fillet(), bd.chamfer()

CAx-Programmierung – D. Straub

Zusatzaufgabe 2: Topologie eines fremden Modells

CAx-Programmierung – D. Straub

STEP-Import

Laden Sie eine STEP-Datei (z.B. aus FreeCAD, GrabCAD oder dem Kursordner):

teil = bd.import_step("mein_teil.step")
CAx-Programmierung – D. Straub

STEP-Analyse und Bearbeitung

  1. Wie viele Faces, Edges, Vertices hat das Teil?
  2. Welche Geometrietypen kommen bei den Flächen vor und wie häufig?
  3. Führen Sie eine sinnvolle Operation durch (z.B. Kreiskanten verrunden, auf einer Fläche aufbauen).

Hinweise: .show_topology(), .faces(), .geom_type, collections.Counter, .filter_by(GeomType.CIRCLE), bd.fillet()

CAx-Programmierung – D. Straub